import java.awt.Point;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

public class ServerEventProcessor extends Thread{
	private ServerMessageSender ms;
	private SynchQueue inbound;
	private Map map;
	private Boolean gameRunning;
	private int nextId = 0;
	private SQLDatabase sql;
	
	public ServerEventProcessor(ServerMessageSender ms, SynchQueue inbound, SQLDatabase sql){
		this.ms = ms;
		map = new Map();
		this.inbound = inbound;
		this.sql=sql;
	}
	
	public void run(){
		try{
		gameRunning = new Boolean(true);
		Iterator entitydata = sql.EntityData().iterator();
		while(entitydata.hasNext()){
			EntityData ent = (EntityData)entitydata.next();
			if(ent instanceof PlayerEntityData){
				initializePlayer((PlayerEntityData)ent);
			}
			else if(ent instanceof EntityData){
				initializeMonster((MonsterEntityData)ent);
			}
		}
		int j=0;
		
		ServerEntity se;
		int i = 0;
		for(Iterator entitydata2 = map.entitySetIterator(); i < 50 && entitydata2.hasNext(); j=0){
			se = (ServerEntity)entitydata2.next();
			if(se instanceof ServerMonsterEntity)
				i++;
		}
		i = 50 - i;
		//i now represents the number of monsters that need to be created
		Random r = new Random();
		while(i >= 0){
			nextId++;
			initializeMonster(new MonsterEntityData(nextId, r.nextInt(3)+2, "chuah" + (new Integer(nextId)).toString(), randomLoc()));
		}
		
		ServerMessage tempin;
		i = 0;
		MonsterTicker monstertick = new MonsterTicker(map,gameRunning);
		monstertick.run();
		ArrayList<ClientMessage> ins = new ArrayList();
		while(gameRunning.booleanValue()){
			for(i = 0; i < 10 && inbound.isEmpty(); i++){
				ins.add((ClientMessage)inbound.dequeue());
			}
			ClientMessage m;
			for(Iterator<ClientMessage> iter = ins.iterator(); iter.hasNext(); j=0){
				m = iter.next();
				if(m instanceof ClientPlayerLoginMessage){
					ServerPlayerEntity p;
					ClientPlayerLoginMessage plm = (ClientPlayerLoginMessage)m;
					PlayerEntityData pdata = null;
					try{
						pdata = (PlayerEntityData)sql.getStoredPlayer(plm.name);
					}catch(Exception e){
						System.out.println(e + " is how Austin Rhodes messed up.");
					}
					if(pdata == null){
						pdata = new PlayerEntityData(nextId++, plm.type, plm.name, randomLoc(), plm.ip);
					}
					p = new ServerPlayerEntity(pdata, map,ms);
					p.data.alive = true;
					p.data.online = true;
					initializePlayer((PlayerEntityData)p.data);
				}
				else if(m instanceof ClientPlayerLogoffMessage){
					ClientPlayerLogoffMessage cplm = (ClientPlayerLogoffMessage)m;
					removePlayer((PlayerEntityData)map.get(cplm.id).data);
				}
				else
					((ServerEntity)map.get(m.id)).processMessage(m);
			}
		}
		}catch(Exception e){
			System.out.println("CHUAH ANGRY. CHUAH SMASH!" + e);
		}
	}
	
	private void initializePlayer(PlayerEntityData data) throws Exception{
		ServerPlayerEntity p = new ServerPlayerEntity(data,map,ms);
		addPlayer(data.ip, data);
		map.add(p);
	}
	
	private void initializeMonster(MonsterEntityData data) throws Exception{
		ServerMonsterEntity m = new ServerMonsterEntity(data,map,ms);
		addMonster(m);
		map.add(m);
	}
	
	public void shutDown(){
		gameRunning = new Boolean(false);
		Iterator iter = map.entitySetIterator();
		while(iter.hasNext()){
			Entity ent = (Entity)iter.next();
			if(ent instanceof ServerPlayerEntity){
				ServerPlayerEntity spe = (ServerPlayerEntity)ent;
				try{
					ms.removePlayer((PlayerEntityData)spe.data);
				}
				catch(Exception e){
					System.out.println(e);
				}
			}
		}
	}
	
	private void addPlayer(InetAddress ip, PlayerEntityData pdata) throws Exception{
		ms.addPlayer(ip, pdata);
		Iterator iter = map.entitySetIterator();
		while(iter.hasNext()){
			Entity ent = (Entity)iter.next();
			if(ent instanceof ServerPlayerEntity){
				ServerPlayerEntity spe = (ServerPlayerEntity)ent;
				ms.specificPlayerPlayerUpdate((PlayerEntityData)spe.data);
			}
			else{// is a monster
				ServerMonsterEntity sme = (ServerMonsterEntity)ent;
				ms.specificPlayerMonsterUpdate((MonsterEntityData)sme.data, pdata.ip);
			}
		}
	}
	private void removePlayer(PlayerEntityData pdata) throws Exception{
		ms.removePlayer(pdata);
		map.remove(pdata.id);
	}
	
	private void addMonster(ServerMonsterEntity ent){
		ms.addMonster((MonsterEntityData)ent.data);
	}
	private void removeMonster(MonsterEntityData data) throws Exception{
		ms.removeMonster(data);
		map.remove(data.id);
	}
	private Point randomLoc(){
		Random r = new Random(50);
		Point loc;
		
		do{
			loc = new Point(r.nextInt(100),r.nextInt(100));
		}while(!map.isEmpty(loc));
		
		return loc;
	}
}

class MonsterTicker extends Thread{
	Boolean run;
	Map map;
	
	public MonsterTicker(Map map, Boolean run){
		this.map = map;
		this.run = run;
	}
	
	public void run(){
		while(run.booleanValue()){
			Iterator iter = map.entitySetIterator();
			while(iter.hasNext()){
				Entity ent = (Entity)iter.next();
				if(ent instanceof ServerMonsterEntity){
					((ServerMonsterEntity)ent).act();
				}
			}
		}
	}
}